using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.Common;
using System.Globalization;
using System.Collections;
using System.Text;
using System.Data;

/// <summary>
/// A page for managing applications
/// </summary>
public partial class Applications : System.Web.UI.Page
{
    private Database db;
    /// <summary>
    /// Disables gridlines if there are no applications
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void Page_Load(object sender, EventArgs e)
    {
        Page.ClientScript.RegisterClientScriptInclude("main", ResolveUrl("~/js/main.js"));
        Page.ClientScript.RegisterClientScriptInclude("main", ResolveUrl("~/js/applications.js"));
        Page.ClientScript.RegisterClientScriptInclude("jquery", "http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js");
        if(!Page.IsPostBack) {
            mltMain.ActiveViewIndex = 0;
            BindApplicationsGrid();
        } else {
            if(mltMain.ActiveViewIndex == 1) {
                SetBundleSelectCommand();
            }
        }
    }

    /// <summary>
    /// Process edit/delete commands from the GridView
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.Web.UI.WebControls.GridViewCommandEventArgs"/> instance containing the event data.</param>
    protected void grdApplications_RowCommand(object sender, GridViewCommandEventArgs e) {
        db = new Database();
        switch(e.CommandName) {
            case "doedit":
                mltMain.ActiveViewIndex = 1;
                using(Database.Command cmd = db.CreateCommand()) {
                    db.OpenConnection();
                    cmd.CommandText = "SELECT * FROM applications WHERE id = @p";
                    cmd.AddParameterWithValue("@p", e.CommandArgument.ToString());
                    DbDataReader reader = cmd.ExecuteReader();
                    string defaultLanguage = string.Empty;
                    string[] selectedLanguages = null;
                    string applicationId = string.Empty;
                    while(reader.Read()) {
                        txtAppName.Text = reader["name"].ToString();
                        txtDisplayName.Text = reader["displayname"].ToString();
                        defaultLanguage = reader["defaultlanguage"].ToString();
                        selectedLanguages = reader["languages"].ToString().Split(',');
                        applicationId = reader["id"].ToString();
                        Page.Title = "Editing " + txtDisplayName.Text+" &raquo; ResourceBlender";
                        lblEditApplications.Text = "Editing " + txtDisplayName.Text;
                        litNavAddAddApplication.Text = "Edit Application";
                    }
                    reader.Close();
                    BindComboOptions(selectedLanguages, defaultLanguage, applicationId);
                }
                break;
            case "confirmdelete":
                mltMain.ActiveViewIndex = 2;
                ViewState["appid"] = e.CommandArgument.ToString();
                using(Database.Command cmd = db.CreateCommand()) {
                    db.OpenConnection();
                    cmd.CommandText = "SELECT displayname FROM applications WHERE id = @p";
                    cmd.AddParameterWithValue("@p", e.CommandArgument.ToString());
                    string applicationName = cmd.ExecuteScalar().ToString();
                    lblConfirmDelete.Text = string.Format("Are you sure you want to delete the application <em>{0}</em> from the database?", applicationName);
                }
                break;
            default:
                mltMain.ActiveViewIndex = 0;
                break;
        }
        db.CloseConnection();
    }

    /// <summary>
    /// Binds the applications GridView and removes gridlines if necessary.
    /// </summary>
    private void BindApplicationsGrid() {
        grdApplications.DataBind();
        if(grdApplications.Rows.Count == 0) {
            grdApplications.GridLines = GridLines.None;
        } else {
            grdApplications.GridLines = GridLines.Both;
        }
    }

    /// <summary>
    /// Binds the bundles GridView and removes gridlines if necessary.
    /// </summary>
    private void BindBundlesGrid() {
        grdBundles.DataBind();
        if(grdBundles.Rows.Count == 0) {
            grdBundles.GridLines = GridLines.None;
        } else {
            grdBundles.GridLines = GridLines.Both;
        }
    }

    #region Adding/Editing
    /// <summary>
    /// Populates the 'Bundles' and language combo boxes
    /// </summary>
    /// <param name="selectedLanguages">The languages included in the application.</param>
    /// <param name="defaultLanguage">The default language.</param>
    private void BindComboOptions(string[] selectedLanguages, string defaultLanguage, string applicationId) {
        CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
        List<ListItem> availableCultures = new List<ListItem>(),
                       selectedCultures = new List<ListItem>(),
                       bundleList = new List<ListItem>();
        foreach(CultureInfo culture in cultures) {
            if(culture.Name.Length > 0) {
                if(selectedLanguages.Contains(culture.Name)) {
                    ListItem itm = new ListItem(culture.EnglishName, culture.Name);
                    selectedCultures.Add(itm);
                } else {
                    availableCultures.Add(new ListItem(culture.EnglishName, culture.Name));
                }
            }
        }
        ListComparer comp = new ListComparer();
        availableCultures.Sort(comp);
        selectedCultures.Sort(comp);
        lstAvailableLangs.Items.AddRange(availableCultures.ToArray());
        lstSelectedLangs.Items.AddRange(selectedCultures.ToArray());
        cboDefaultLanguage.Items.AddRange(selectedCultures.ToArray());
        cboDefaultLanguage.SelectedValue = defaultLanguage;
        string appId = applicationId == null ? Utils.GenID(true) : applicationId;
        SetBundleSelectCommand();
        if(dsBundles.SelectParameters.Count == 0) {
            dsBundles.SelectParameters.Add("application", DbType.String, appId);
        } else {
            dsBundles.SelectParameters["application"].DefaultValue = appId;
        }
        if(dsBundles.UpdateParameters.Count == 0) {
            dsBundles.UpdateParameters.Add("name", DbType.String, appId);
            dsBundles.UpdateParameters.Add("id", DbType.String, appId);
        } else {
            dsBundles.UpdateParameters["name"].DefaultValue = appId;
            dsBundles.UpdateParameters["id"].DefaultValue = appId;
        }
        BindApplicationsGrid();
        ViewState["appid"] = appId;
        ViewState["editing"] = applicationId == null ? bool.FalseString : bool.TrueString;
        BindBundlesGrid();
    }

    /// <summary>
    /// Sets the select command for the bundles DataSource (depending on the type of SQL server).
    /// </summary>
    private void SetBundleSelectCommand() {
        switch(Constants.DatabaseInstanceType) {
            case Database.DatabaseType.MySQL:
                dsBundles.SelectCommand = "SELECT id, name FROM bundles WHERE application = ?application";
                dsBundles.UpdateCommand = "UPDATE bundles SET name = ?name WHERE id = ?id";
                break;
            case Database.DatabaseType.SQLServer:
                dsBundles.SelectCommand = "SELECT id, name FROM bundles WHERE application = @application";
                dsBundles.UpdateCommand = "UPDATE bundles SET name = @name WHERE id = @id";
                break;
        }
    }

    /// <summary>
    /// Shows a form to add a new application/
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void lnkAddApplication_Click(object sender, EventArgs e) {
        mltMain.ActiveViewIndex = 1;
        Page.Title = "Add Application &raquo; ResourceBlender";
        BindComboOptions(new string[]{}, "", null);
    }

    /// <summary>
    /// Validates one or more languages are selected.
    /// </summary>
    /// <param name="source">The source.</param>
    /// <param name="args">The <see cref="System.Web.UI.WebControls.ServerValidateEventArgs"/> instance containing the event data.</param>
    protected void validateHasLanguages(object source, ServerValidateEventArgs args) {
        args.IsValid = lstSelectedLangs.Items.Count > 0;
    }

    /// <summary>
    /// Moves a language from 'Selected languages' to 'Available languages'
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnRemoveLang_Click(object sender, EventArgs e) {
        if(lstSelectedLangs.SelectedItem == null) {
            return;
        }
        List<ListItem> newItems = new List<ListItem>(lstAvailableLangs.Items.Count);
        foreach(ListItem availableLanguage in lstAvailableLangs.Items) {
            newItems.Add(availableLanguage);
        }
        ListItem selectedLanguage;
        for(int i = lstSelectedLangs.Items.Count - 1; i >= 0; i--) {
            selectedLanguage = lstSelectedLangs.Items[i];
            if(selectedLanguage.Selected) {
                lstSelectedLangs.Items.Remove(selectedLanguage);
                cboDefaultLanguage.Items.Remove(selectedLanguage);
                selectedLanguage.Selected = false;
                newItems.Add(selectedLanguage);
            }
        }
        newItems.Sort(new ListComparer());
        lstAvailableLangs.Items.Clear();
        ListItem[] newAvailableLangs = newItems.ToArray();
        lstAvailableLangs.Items.AddRange(newAvailableLangs);
    }

    /// <summary>
    /// Moves a language from 'Available languages' to 'Selected languages'
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnAddLang_Click(object sender, EventArgs e) {
        if(lstAvailableLangs.SelectedItem == null) {
            return;
        }
        List<ListItem> newItems = new List<ListItem>(lstSelectedLangs.Items.Count);
        foreach(ListItem currentLanguage in lstSelectedLangs.Items) {
            newItems.Add(currentLanguage);
        }
        ListItem availableLanguage;
        for(int i=lstAvailableLangs.Items.Count-1;i>=0;i--) {
            availableLanguage = lstAvailableLangs.Items[i];
            if(availableLanguage.Selected) {
                lstAvailableLangs.Items.Remove(availableLanguage);
                availableLanguage.Selected = false;
                newItems.Add(availableLanguage);
            }
        }
        newItems.Sort(new ListComparer());
        lstSelectedLangs.Items.Clear();
        ListItem[] newSelectedLangs = newItems.ToArray();
        lstSelectedLangs.Items.AddRange(newSelectedLangs);
        string currentDefaultLang = cboDefaultLanguage.SelectedValue;
        cboDefaultLanguage.Items.Clear();
        cboDefaultLanguage.Items.AddRange(newSelectedLangs);
        if(currentDefaultLang != null && currentDefaultLang.Length > 0) {
            cboDefaultLanguage.SelectedValue = currentDefaultLang;
        }
    }

    /// <summary>
    /// Processes edit/delete commands from the bundles GridView
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.Web.UI.WebControls.GridViewCommandEventArgs"/> instance containing the event data.</param>
    protected void grdBundles_RowCommand(object sender, GridViewCommandEventArgs e) {
        switch(e.CommandName) {
            case "deletebundle":
                db = new Database();
                db.OpenConnection();
                using(Database.Command cmd = db.CreateCommand()) {
                    cmd.CommandText = "DELETE FROM bundles WHERE id = @p";
                    cmd.AddParameterWithValue("@p", e.CommandArgument.ToString());
                    cmd.ExecuteNonQuery();
                }
                db.CloseConnection();
                BindBundlesGrid();
                break;
        }
    }
      
    /// <summary>
    /// Adds a new bundle
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnAddBundle_Click(object sender, EventArgs e) {
        string bundleName = txtNewBundle.Text.Trim();
        if(bundleName.Length > 0) {
            db = new Database();
            db.OpenConnection();
            using(Database.Command cmd = db.CreateCommand()) {
                cmd.CommandText = "SELECT COUNT(id) FROM bundles WHERE name = @name AND application = @application";
                cmd.AddParameterWithValue("@name", bundleName);
                cmd.AddParameterWithValue("@application", ViewState["appid"].ToString());
                int numExistingBundles = int.Parse(cmd.ExecuteScalar().ToString());
                if(numExistingBundles > 0) {
                    lblAddError.Visible = true;
                } else {
                    cmd.CommandText = "INSERT INTO bundles (id, name, application) VALUES (@id, @name, @application)";
                    cmd.AddParameterWithValue("@id", Utils.GenID(true));
                    cmd.ExecuteNonQuery();
                    BindBundlesGrid();
                    lblAddError.Visible = false;
                    lblNoBundles.Visible = false;
                    txtNewBundle.Text = "";
                }
            }
            db.CloseConnection();
        }
    }

    /// <summary>
    /// Sets the default buttons for the grid controls.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void updBundles_PreRender(object sender, EventArgs e) {
        // removed for now, was firing the add language button
        /*StringBuilder jQueryBuffer = new StringBuilder("var prm = Sys.WebForms.PageRequestManager.getInstance(); prm.add_endRequest(function() {\n");
        jQueryBuffer.Append("$(\"#").Append(txtNewBundle.ClientID).Append("\").keyup(function(event){if(event.keyCode == 13){$(\"#").Append(btnAddBundle.ClientID).Append("\").click();}});\n");
        if(grdBundles.EditIndex >= 0) {

        }
        jQueryBuffer.Append("});");
        ScriptManager.RegisterStartupScript(this, typeof(Page), "addbundlebutton", jQueryBuffer.ToString(), true);*/

    }

    /// <summary>
    /// Saves or adds the application.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnSave_Click(object sender, EventArgs e) {
        Page.Validate("vldLanguages");
        if(Page.IsValid) {
            bool editing = false;
            string applicationId = null;
            try {
                editing = bool.Parse(ViewState["editing"].ToString());
                applicationId = ViewState["appid"].ToString();
            } catch {
                mltMain.ActiveViewIndex = 3;
                lblErrorDescription.Text = "Error loading viewstate data, try refreshing the page.";
                return;
            }
            if(db == null) {
                db = new Database();
            }
            db.OpenConnection();
            using(Database.Command cmd = db.CreateCommand()) {
                cmd.CommandText = "SELECT COUNT(id) FROM bundles WHERE application = @application";
                cmd.AddParameterWithValue("@application", applicationId);
                int numExistingBundles = int.Parse(cmd.ExecuteScalar().ToString());
                if(numExistingBundles == 0) {
                    lblNoBundles.Visible = true;
                } else {
                    lblNoBundles.Visible = false;
                    if(editing) {
                        cmd.CommandText = "UPDATE applications SET displayname = @displayname, name = @name, defaultlanguage = @defaultlanguage, languages = @languages WHERE id = @id";
                        cmd.AddParameterWithValue("@id", applicationId);
                    } else {
                        cmd.CommandText = "INSERT INTO applications (displayname, name, id, defaultlanguage, languages) VALUES (@displayname, @name, @id, @defaultlanguage, @languages)";
                        cmd.AddParameterWithValue("@id", applicationId);
                    }
                    cmd.AddParameterWithValue("@displayname", txtDisplayName.Text);
                    cmd.AddParameterWithValue("@name", txtAppName.Text);
                    cmd.AddParameterWithValue("@defaultlanguage", cboDefaultLanguage.SelectedValue);
                    List<string> selectedLangs = new List<string>();
                    foreach(ListItem itm in lstSelectedLangs.Items) {
                        selectedLangs.Add(itm.Value);
                    }
                    cmd.AddParameterWithValue("@languages", Utils.Implode(selectedLangs, ",", true));
                    cmd.ExecuteNonQuery();
                    mltMain.ActiveViewIndex = 0;
                    BindApplicationsGrid();
                    txtAppName.Text = "";
                    txtDisplayName.Text = "";
                    txtNewBundle.Text = "";
                    cboDefaultLanguage.SelectedIndex = -1;
                    cboDefaultLanguage.Items.Clear();
                    lstAvailableLangs.SelectedIndex = -1;
                    lstAvailableLangs.Items.Clear();
                    lstSelectedLangs.SelectedIndex = -1;
                    lstSelectedLangs.Items.Clear();
                    
                }
            }
            db.CloseConnection();
        }
    }
    #endregion

    #region Deleting
    /// <summary>
    /// Confirms deletion of a application and removes it from the database.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnOk_Click(object sender, EventArgs e) {
        db = new Database();
        db.OpenConnection();
        using(Database.Command cmd = db.CreateCommand()) {
            cmd.CommandText = "DELETE FROM applications WHERE id = @p";
            cmd.AddParameterWithValue("@p", ViewState["appid"].ToString());
            cmd.ExecuteNonQuery();
            cmd.CommandText = "DELETE FROM bundles WHERE application = @p";
            cmd.ExecuteNonQuery();
            cmd.CommandText = "DELETE FROM elements WHERE application = @p";
            cmd.ExecuteNonQuery();
        }
        db.CloseConnection();
        mltMain.ActiveViewIndex = 0;
        BindApplicationsGrid();
    }
    
    /// <summary>
    /// Redirects the user to the 'Manage applications' page.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnCancelDelete_Click(object sender, EventArgs e) {
        mltMain.ActiveViewIndex = 0;
    }
    #endregion

}
